﻿using Flurl.Http;
using NSwag;
//using Microsoft.OpenApi;
//using Microsoft.OpenApi.Extensions;
//using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Anno.Swagger
{
    public class ApiSwagger
    {
        /// <summary>
        /// Anno文档转换成 swagger Json
        /// </summary>
        /// <param name="annoDocUrl"></param>
        /// <returns></returns>
        public static string SwaggerAnnoJson(string annoDocUrl = "http://49.232.112.70", string appName = "HelloWorld")
        {
            string swaggerJson = string.Empty;
            if (!string.IsNullOrWhiteSpace(annoDocUrl))
            {
                var apis = $"{annoDocUrl}/AnnoApi/Anno.Plugs.Trace/Router/GetRoutingInfo?appName={appName}".WithHeader("Content-Type", "application/json")
                 .GetAsync().ReceiveJson<ActionResult<List<AnnoApiDoc>>>().Result;
                return BuildSwaggerApi(apis.OutputData, annoDocUrl, appName).ToJson();
            }
            return swaggerJson;
        }

        private static OpenApiDocument BuildSwaggerApi(List<AnnoApiDoc> apiDocs, string annoDocUrl, string appName)
        {
            var document = new OpenApiDocument()
            {
                Info = new OpenApiInfo
                {
                    Version = "1.0.0",
                    Title = $"Swagger Anno ({appName})",
                },
                Host = annoDocUrl,
                BasePath = "/AnnoApi",
                Tags = BuildOpenApiTags(apiDocs)
            };
            BuildOpenApiPaths(document, apiDocs);
            return document;
        }
        public static void BuildOpenApiPaths(OpenApiDocument document, List<AnnoApiDoc> apiDocs)
        {
            if (apiDocs != null)
            {
                foreach (var doc in apiDocs)
                {
                    //var channel = doc.Channel.EndsWith("Service", StringComparison.OrdinalIgnoreCase) ? doc.Channel.Substring(0, doc.Channel.Length - 7) : doc.Channel;
                    //var router = doc.Router.EndsWith("Module", StringComparison.OrdinalIgnoreCase) ? doc.Router.Substring(0, doc.Router.Length - 6) : doc.Router;
                    var path = $"/{doc.RoutePrefix.Trim('/')}";// $"/{channel}/{router}/{doc.Method}";
                    if (!document.Paths.ContainsKey(path))
                        document.Paths.Add(path, BuildOpenApiPathItem(doc));
                }
            }
        }

        public static List<OpenApiTag> BuildOpenApiTags(List<AnnoApiDoc> apiDocs)
        {
            var tags = new List<OpenApiTag>();
            if (apiDocs != null)
            {
                var channels = apiDocs.Select(tag => tag.Channel).Distinct();
                foreach (var channel in channels)
                {
                    tags.Add(new OpenApiTag()
                    {
                        Name = channel,
                        Description = channel
                    });
                }
            }
            return tags;
        }
        public static OpenApiPathItem BuildOpenApiPathItem(AnnoApiDoc doc)
        {
            var httpMethod = "POST";
            if (doc?.Value != null && !string.IsNullOrWhiteSpace(doc.Value.HttpMethod))
                httpMethod = doc.Value.HttpMethod;

            var pathItem = new OpenApiPathItem()
            {
                Parameters = new List<OpenApiParameter>(),
                Description = doc.Desc
            };
            if (doc?.Value?.Parameters != null)
            {
                foreach (var item in doc.Value.Parameters)
                {
                    var openApiParameter = new OpenApiParameter
                    {
                        Name = item.Name,
                        Format = item.ParameterType,
                        Kind = httpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase) ? OpenApiParameterKind.Query : OpenApiParameterKind.FormData,
                        Description = item.Desc,

                    };
                    pathItem.Parameters.Add(openApiParameter);
                }
            }
            pathItem.Summary = doc.Desc;
            var operation = new OpenApiOperation()
            {
                Summary = doc.Desc,
                Tags = new List<string>() { doc.Channel }
            };

            //if (!httpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase))
            {
                operation.Responses.Add("200", new OpenApiResponse()
                {
                    Description = string.IsNullOrWhiteSpace(doc.Desc) ? "OK" : doc.Desc
                });
            }
            pathItem.Add(httpMethod, operation);
            return pathItem;
        }
    }
}
